package com.lcy.struct.bTreePlus.property;

import com.lcy.struct.bTreePlus.disk.constants.BPlusPublicConstants;
import com.lcy.struct.bTreePlus.disk.log.LogUtils;
import com.lcy.struct.bTreePlus.disk.file.FileUtil;
import lombok.Data;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author lucongyang
 * @date Created in  11:22
 * @description
 */
@Data
public class BPlusFileInfo {
    private static ReentrantReadWriteLock END_POINT_LOCK = new ReentrantReadWriteLock();
    public static final Lock END_POINT_WRITE_LOCK = END_POINT_LOCK.writeLock();
    public static final Lock END_POINT_READ_LOCK = END_POINT_LOCK.readLock();
    private static ReentrantReadWriteLock COUNT_LOCK = new ReentrantReadWriteLock();
    private static final Lock COUNT_WRITE_LOCK = END_POINT_LOCK.writeLock();
    private static final Lock COUNT_READ_LOCK = END_POINT_LOCK.readLock();
    private static ReentrantReadWriteLock ROOT_POSITION_LOCK = new ReentrantReadWriteLock();
    private static final Lock ROOT_POSITION_WRITE_LOCK = END_POINT_LOCK.writeLock();
    private static final Lock ROOT_POSITION_READ_LOCK = END_POINT_LOCK.readLock();
    /**
     * 总数
     */
    private static Integer count;
    /**
     * 根节点地址
     */
    private static Long rootPosition;
    /**
     * B+tree阶数
     */
    private static Integer rankBPlusTree;
    /**
     * 文件末尾指针位置
     */
    public static Long endPosition;

    public static Long getRootPosition() {
        if (rootPosition != null) {
            return rootPosition;
        }
        byte[] infoBytes = FileUtil.getInstance().read(BPlusPublicConstants.ROOT_POSITION_INFO_POSITION, BPlusPublicConstants.HEAD_SIZE);
        if (infoBytes.length > 0) {
            String s = new String(infoBytes).trim();
            if (!s.isEmpty()) {
                rootPosition = Long.parseLong(s);
            }
        }
        return rootPosition;
    }

    public static void setRootPosition(Long position) {
        rootPosition = position;
    }

    public static void saveRootPosition() {
        Long rootPosition = getRootPosition();
        saveRootPosition(rootPosition);
    }

    public static void saveRootPosition(long rootPosition) {
        FileUtil.getInstance().rewriteForce(BPlusPublicConstants.ROOT_POSITION_INFO_POSITION, BPlusPublicConstants.HEAD_SIZE, (rootPosition + "").getBytes());
    }

    public static Integer getRankBPlusTree() {
        if (rankBPlusTree != null) {
            return rankBPlusTree;
        }
        byte[] infoBytes = FileUtil.getInstance().read(BPlusPublicConstants.RANK_BPLUS_TREE_INFO_POSITION, BPlusPublicConstants.HEAD_SIZE);
        if (infoBytes.length > 0) {
            String s = new String(infoBytes).trim();
            if (!s.isEmpty()) {
                rankBPlusTree = Integer.parseInt(s);
            }
        }
        boolean isnull = rankBPlusTree == null;
        rankBPlusTree = rankBPlusTree != null ? rankBPlusTree : BPlusPublicConstants.DEFAULT_RANK_BPLUS_TREE;
        if (isnull) {
            saveRankBPlusTree();
        }
        return rankBPlusTree;
    }

    public static void saveRankBPlusTree() {
        Integer rankBplusTree = getRankBPlusTree();
        LogUtils.log("持久化阶数={}", rankBplusTree);
        FileUtil.getInstance().rewrite(BPlusPublicConstants.RANK_BPLUS_TREE_INFO_POSITION, BPlusPublicConstants.HEAD_SIZE, (rankBplusTree + "").getBytes());
    }

    public static Long getEndPosition() {
        END_POINT_READ_LOCK.lock();
        try {
            if (endPosition != null) {
                return endPosition;
            }
            byte[] infoBytes = FileUtil.getInstance().read(BPlusPublicConstants.END_POSITION_INFO_POSITION, BPlusPublicConstants.HEAD_SIZE);
            if (infoBytes.length > 0) {
                String s = new String(infoBytes).trim();
                if (!s.isEmpty()) {
                    endPosition = Long.parseLong(s);
                } else {
                    endPosition = (long) BPlusPublicConstants.ALL_HEAD_SIZE;
                }
            } else {
                endPosition = (long) BPlusPublicConstants.ALL_HEAD_SIZE;
            }
            return endPosition;
        } finally {
            END_POINT_READ_LOCK.unlock();
        }
    }

    public static void saveEndPosition() {
        END_POINT_WRITE_LOCK.lock();
        try {
            Long endPosition = getEndPosition();
            saveEndPosition(endPosition);
        } finally {
            END_POINT_WRITE_LOCK.unlock();
        }
    }

    public static void saveEndPosition(long giveEndPosition) {
        END_POINT_WRITE_LOCK.lock();
        try {
            FileUtil.getInstance().rewriteForce(BPlusPublicConstants.END_POSITION_INFO_POSITION, BPlusPublicConstants.HEAD_SIZE, (giveEndPosition + "").getBytes());
            endPosition = giveEndPosition;
        } finally {
            END_POINT_WRITE_LOCK.unlock();
        }
    }

    public static Integer getCount() {
        if (count != null) {
            return count;
        }
        byte[] infoBytes = FileUtil.getInstance().read(BPlusPublicConstants.COUNT_POSITION_INFO_POSITION, BPlusPublicConstants.HEAD_SIZE);
        if (infoBytes.length > 0) {
            String s = new String(infoBytes).trim();
            if (!s.isEmpty()) {
                count = Integer.parseInt(s);
            }
        }
        count = count != null ? count : 0;
        return count;
    }

    public static void countAddOne() {
        getCount();
        count++;
    }

    public static void countMinusOne() {
        getCount();
        count--;
    }

    public static void saveCount() {
        Integer count = getCount();
        saveCount(count);
    }

    public static void saveCount(int count) {
        FileUtil.getInstance().rewrite(BPlusPublicConstants.COUNT_POSITION_INFO_POSITION, BPlusPublicConstants.HEAD_SIZE, (count + "").getBytes());
    }

    /**
     * 分配磁盘空间
     *
     * @return 开始位置
     */
    public static long allocate(int size) {
        END_POINT_WRITE_LOCK.lock();
        try {
            Long l = getEndPosition();
            endPosition = l + size;
            return l;
        } finally {
            END_POINT_WRITE_LOCK.unlock();
        }
    }

    /**
     * 加载配置到内存
     */
    public static void reloadProperties() {
        getEndPosition();
        getRootPosition();
        getRankBPlusTree();
    }
}
